/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.inspur.edp.lcm.metadata.common;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.inspur.edp.lcm.metadata.api.IMdExtRuleContent;
import com.inspur.edp.lcm.metadata.api.IMetadataContent;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.common.configuration.MdExtRuleSerializerHelper;
import com.inspur.edp.lcm.metadata.common.configuration.MetadataSerializerHelper;
import com.inspur.edp.lcm.metadata.spi.MdExtendRuleSerializer;
import com.inspur.edp.lcm.metadata.spi.MetadataContentSerializer;
import io.iec.edp.caf.caching.api.RedisDataSerializer;
import java.io.IOException;
import lombok.var;

public class MetadataSerializer implements RedisDataSerializer {
	private ObjectMapper mapper = ServiceUtils.getMapper();

	@Override
	public <T> T deserialize(String fileString, Class<T> clazz) {
		if (fileString == null || fileString.isEmpty()) {
			return null;
		}
		try {
			IMetadataContent metadataContent;
			JsonNode metadataObj = mapper.readTree(fileString);
			GspMetadata metadata = buildMetadataBaseInfo(metadataObj);

			//IMetdataContent需要调用各元数据反序列化
			MetadataContentSerializer manager = MetadataSerializerHelper.getInstance().getManager(metadata.getHeader().getType());
			if (manager == null) {
				throw new RuntimeException("未能正常获取元数据序列化器，请检查配置,元数据类型为："+metadata.getHeader().getType());
			}
			JsonNode content = metadataObj.findValue(MetadataPropertyUtils.content);
			metadataContent = content.isTextual() ? manager.DeSerialize(mapper.readTree(handleJsonString(content.toString()))) : manager.DeSerialize(content);
			if (metadataContent == null) {
				throw new RuntimeException("反序列化的content为null：" + fileString);
			}
			metadata.setContent(metadataContent);
			JsonNode extRule = metadataObj.findValue(MetadataPropertyUtils.extendRule);
			if (extRule != null) {
				MdExtendRuleSerializer mdExtRulemanager = MdExtRuleSerializerHelper.getInstance().getManager(metadata.getHeader().getType());
				if (mdExtRulemanager != null) {
					JsonNode handledContent = mapper.readTree(extRule.toString());
					IMdExtRuleContent extRuleContent = mdExtRulemanager.deSerialize(handledContent);
					metadata.setExtendRule(extRuleContent);
				}
			}

			return (T) metadata;
		} catch (RuntimeException | IOException e) {
			throw new RuntimeException("反序列化元数据失败", e);
		}
	}

	public GspMetadata buildMetadataBaseInfo(JsonNode metadataObj) {
		GspMetadata metadata;
		try {
			String headerStr = metadataObj.findValue(MetadataPropertyUtils.header).toString();
			var refNode = metadataObj.findValue(MetadataPropertyUtils.refs);
			String constraintsStr;
			if (refNode == null) {
				constraintsStr = "[]";
			} else {
				constraintsStr = refNode.toString();
			}

			var extendPropertyNode = metadataObj.findValue(MetadataPropertyUtils.extendProperty);
			var extendedNode = metadataObj.findValue(MetadataPropertyUtils.extended);
			var properties = metadataObj.findValue(MetadataPropertyUtils.properties);
			var version = metadataObj.findValue(MetadataPropertyUtils.version);
			var previousVersion = metadataObj.findValue(MetadataPropertyUtils.previousVersion);
			var relativePath = metadataObj.findValue(MetadataPropertyUtils.relativePath);
			String extendPropertyStr = (extendPropertyNode == null || extendPropertyNode.toString().equals("null") ) ? "\"\"" : extendPropertyNode.toString();
			String metadataStr = String.format("{\"%s\":%s,\"%s\":%s,\"%s\":null,\"%s\":%s,\"%s\":%s,\"%s\":%s,\"%s\":%s,\"%s\":%s,\"%s\":%s,\"%s\":null}",
					MetadataPropertyUtils.header,headerStr, MetadataPropertyUtils.refs,constraintsStr,MetadataPropertyUtils.content,MetadataPropertyUtils.extendProperty,
					extendPropertyStr,MetadataPropertyUtils.extended, extendedNode,MetadataPropertyUtils.properties, properties,MetadataPropertyUtils.version, version,
					MetadataPropertyUtils.previousVersion, previousVersion,MetadataPropertyUtils.relativePath, relativePath,MetadataPropertyUtils.extendRule);
			metadata = this.mapper.readValue(metadataStr, GspMetadata.class);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}

		return metadata;
	}

	public static ObjectMapper getMapper() {
		ObjectMapper mapper = new ObjectMapper();
		mapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
		mapper.configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true);
		mapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
		mapper.configure(JsonParser.Feature.ALLOW_MISSING_VALUES, true);
		mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);//大小写脱敏 默认为false  需要改为tru
		return mapper;
	}

	private static String handleJsonString(String contentJson) {
		if (contentJson.startsWith("\"{\\\"")) {

			contentJson = contentJson.replace("\\\"", "\"");
			while (contentJson.startsWith("\"")) {
				contentJson = contentJson.substring(1, contentJson.length() - 1);
			}
		}
		return contentJson;
	}

	@Override
	public String serialize(Object o) {
		GspMetadata metadata = (GspMetadata) o;
		MetadataContentSerializer manager = MetadataSerializerHelper.getInstance().getManager(metadata.getHeader().getType());
		if (manager == null) {
			throw new RuntimeException("未能正常获取" + metadata.getHeader().getType() + "的序列化器，请检查配置");
		}
		JsonNode jsonNode = manager.Serialize(metadata.getContent());
		JsonNode extRuleNode = null;
		if (metadata.getExtendRule() != null) {
			var mdExtRulemanager = MdExtRuleSerializerHelper.getInstance().getManager(metadata.getHeader().getType());
			if (mdExtRulemanager != null) {
				extRuleNode = mdExtRulemanager.serialize(metadata.getExtendRule());
			}
		}

		ObjectMapper objectMapper = ServiceUtils.getMapper();
		GspMetadata newMetadata = (GspMetadata) metadata.clone();
		String metadataStr;
		try {
			metadataStr = objectMapper.writeValueAsString(newMetadata);
			JsonNode metadataObj = objectMapper.readTree(metadataStr);
			ObjectNode objNode = (ObjectNode) metadataObj;
			objNode.set(MetadataPropertyUtils.content, jsonNode);
			objNode.set(MetadataPropertyUtils.extendRule, extRuleNode);
			metadataStr = objectMapper.writeValueAsString(objNode);
		} catch (JsonProcessingException e) {
			throw new RuntimeException("序列化元数据失败：" + metadata.getHeader().getId(), e);
		}
		return metadataStr;
	}
}
